﻿using System;
using System.Collections.Generic;
using System.Linq;

using Microsoft.Xna.Framework;

namespace WorldOnFire
{
    public class CBuildable
    {
        #region Managers

        private static CRandom s_Ron = new CRandom();

        private static CObjectManager s_ObjectManager;

        public static void SetObjectManager(CObjectManager _ObjectManager)
        { s_ObjectManager = _ObjectManager; }

        #endregion Managers

        #region Buildable Data

        // Turret data
        private List<ABCTurret.eTurretType> m_TurretTypeList;
        private List<int> m_TurretIndexList;

        private int m_nMaxTurretCount;
        private int m_nCurrentTurretCount;
        private float m_fMaximumRange;

        // Turret targeting data
        private List<int>[] m_EnemyIndexList;
        private int m_nEnemyCount;

        // Orbit data
        private float m_fOrbitRadius;

        // Targeting
        private float m_fTargetingTimer;
        private List<int> m_NoTargetList;

        #endregion Buildable Data

        #region Accessors and Mutators

        public bool HasMaximumNumberOfTurrets()
        { return m_nCurrentTurretCount == m_nMaxTurretCount; }

        public float GetOrbitRadius()
        { return m_fOrbitRadius; }

        #endregion Accessors and Mutators

        #region Turret Creation and Destruction

        public void CreateTurret(ABCTurret.eTurretType _eType)
        {
            // If the maximum number of turrets has already been reached
            if (this.HasMaximumNumberOfTurrets() == true)
            {
                // EJECT
                return;
            }

            // Get the turret from the object manager
            ABCTurret Turret = s_ObjectManager.GetTurret(_eType);

            // Create a turret and store its index
            int nTurretIndex = Turret.CreateTurret(this);

            // If the turret was created
            if (nTurretIndex != -1)
            {
                // Set the turret to active
                Turret.ScheduleForActivation(nTurretIndex);

                // Add the turret's data to the lists
                m_TurretTypeList.Add(_eType);
                m_TurretIndexList.Add(nTurretIndex);

                // If the turret's range exceeds the current maximum range
                if (Turret.GetRange(nTurretIndex) > m_fMaximumRange)
                {
                    // Reset the maximum range
                    m_fMaximumRange = Turret.GetRange(nTurretIndex);
                }

                // Increment the number of turrets
                ++m_nCurrentTurretCount;
            }

            // TODO: CATCH ON FIRE
        }

        public void DestroyTurret(ABCTurret.eTurretType _eType, int _nIndex)
        {
            // Loop through the list of types
            for (int iType = 0; iType < m_TurretTypeList.Count; ++iType)
            {
                // If this is the correct turret type
                if (m_TurretTypeList[iType] == _eType)
                {
                    // If the corresponding turret index is correct
                    if (m_TurretIndexList[iType] == _nIndex)
                    {
                        // Get the turret from the object manager
                        ABCTurret Turret = s_ObjectManager.GetTurret(_eType);

                        // Set the turret to inactive
                        Turret.ScheduleForDeactivation(_nIndex);

                        // Remove the turret's data from the lists
                        m_TurretTypeList.RemoveAt(iType);
                        m_TurretIndexList.RemoveAt(iType);

                        // Decrement the number of turrets
                        --m_nCurrentTurretCount;

                        // If the turret's range was the maximum range
                        if (Turret.GetRange(_nIndex) == m_fMaximumRange)
                        {
                            // Reset the maximum range
                            m_fMaximumRange = 0.0f;

                            // Loop through each turret and check its range against the maximum range
                            for (int iTurret = 0; iTurret < m_nCurrentTurretCount; ++iTurret)
                            {
                                // If the turret's range was the  maximum range
                                if (Turret.GetRange(iTurret) > m_fMaximumRange)
                                {
                                    // Reset the maximum range
                                    m_fMaximumRange = Turret.GetRange(iTurret);
                                }
                            }
                        }
                    }
                }
            }

            // TODO: CATCH ON FIRE
        }

        #endregion Turret Creation and Destruction

        #region Initialization

        public void Initialize(float _fCelestialBodyRadius)
        {
            // Initialize members
            m_TurretTypeList = new List<ABCTurret.eTurretType>();
            m_TurretIndexList = new List<int>();

            m_EnemyIndexList = new List<int>[(int)ABCEnemy.eEnemyType.COUNT];
            for (int iEnemyType = 0; iEnemyType < (int)ABCEnemy.eEnemyType.COUNT; ++iEnemyType)
            {
                m_EnemyIndexList[iEnemyType] = new List<int>();
            }

            // Determine the maximum number of turrets based on this bullshit formula
            m_nMaxTurretCount = (int)(0.1f * _fCelestialBodyRadius);

            m_NoTargetList = new List<int>();

            // Set orbit distance
            m_fOrbitRadius = 1.25f * _fCelestialBodyRadius + 25.0f;
        }

        public void Shutdown()
        {

        }

        #endregion Initialization

        #region Update

        public void Update(float _fDeltaTime, Vector3 _vCenterOfOrbit)
        {
            // If there are turrets
            if (m_nCurrentTurretCount > 0)
            {
                // Increment the targeting timer
                m_fTargetingTimer += _fDeltaTime;

                // If its been a second since targets were scanned for
                if(m_fTargetingTimer > 0.1f)
                {
                    // Reset the targeting timer
                    m_fTargetingTimer = 0.0f;

                    // Loop through each turret
                    for(int iTurret = 0; iTurret < m_nCurrentTurretCount; ++iTurret)
                    {
                        // Store the turret
                        ABCTurret Turret = s_ObjectManager.GetTurret(m_TurretTypeList[iTurret]);

                        // If the turret has no target
                        if(Turret.HasTarget(m_TurretIndexList[iTurret]) == false)
                        {
                            // Add the turret's local index to the list of turrets that need targets
                            m_NoTargetList.Add(iTurret);
                        }
                    }
                }


                // If any turrets need targets (make this check only happen once every second or so)
                if (m_NoTargetList.Count > 0)
                {
                    m_nEnemyCount = 0;

                    // For each enemy type
                    for (int iEnemyType = 0; iEnemyType < (int)ABCEnemy.eEnemyType.COUNT; ++iEnemyType)
                    {
                        // Cull the list of enemies using maximum range
                        m_EnemyIndexList[iEnemyType] = 
                            s_ObjectManager.GetEnemy((ABCEnemy.eEnemyType)iEnemyType)
                            .GetCollidingIndexList(_vCenterOfOrbit, m_fMaximumRange);

                        m_nEnemyCount += m_EnemyIndexList[iEnemyType].Count;
                    }

                    // If there are targets
                    if (m_nEnemyCount > 0)
                    {
                        // Loop through each turret needing a target
                        for (int iTurret = 0; iTurret < m_NoTargetList.Count; ++iTurret)
                        {
                            ABCTurret Turret = s_ObjectManager.GetTurret(m_TurretTypeList[m_NoTargetList[iTurret]]);

                            ABCEnemy.eEnemyType[] ePreferredTargets = Turret.GetPrefferedEnemies();

                            for (int iEnemyType = 0; iEnemyType < (int)ABCEnemy.eEnemyType.COUNT; ++iEnemyType)
                            {
                                if (m_EnemyIndexList[(int)ePreferredTargets[iEnemyType]].Count > 0)
                                {
                                    ABCEnemy Enemy = s_ObjectManager.GetEnemy(ePreferredTargets[iEnemyType]);
                                    Turret.SetTarget(m_TurretIndexList[m_NoTargetList[iTurret]],
                                        ePreferredTargets[iEnemyType],
                                        m_EnemyIndexList[(int)ePreferredTargets[iEnemyType]]
                                        [s_Ron.Next(m_EnemyIndexList[(int)ePreferredTargets[iEnemyType]].Count)]);
                                    break;
                                }
                            }
                        }

                        // Clear the list of turrets that need targets
                        m_NoTargetList.Clear();
                    }
                }

                // Loop through each turret
                for (int iTurret = 0; iTurret < m_nCurrentTurretCount; ++iTurret)
                {
                    ABCTurret Turret = s_ObjectManager.GetTurret(m_TurretTypeList[iTurret]);

                    // TODO: Set center of orbit
                    Turret.SetCenterOfOrbit(m_TurretIndexList[iTurret], _vCenterOfOrbit);

                    // If the turret has a target
                    {
                        // If the target is no longer in range
                        {
                            // TODO: Release the target
                        }
                    }
                    // If the turret does not have a target
                    {
                        // TODO: Acquire targets

                        // For each set of targets (WANT, MEH, DO_NOT_WANT)
                        {
                            // Check the culled list for anything in range
                        }
                    }
                }
            }
        }

        #endregion Update
    }
}
